package cn.lizemin.fakedata.security.filters;

import cn.lizemin.fakedata.common.RespBean;
import cn.lizemin.fakedata.common.ResultEnum;
import cn.lizemin.fakedata.security.SecurityContextHolder;
import cn.lizemin.fakedata.security.UserDetails;
import cn.lizemin.fakedata.security.annotation.PreAuthorize;
import cn.lizemin.fakedata.utils.JSON;
import cn.lizemin.fakedata.utils.SecurityUtil;
import lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * @author lzm
 * @Date 2024/7/7
 * @description
 */
@WebFilter("/*")
@Component
@Order(10)
public class PermissionFilter extends OncePerRequestFilter {

    private static final Logger log = LoggerFactory.getLogger(PermissionFilter.class);

    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Autowired
    RequestMappingHandlerMapping handlerMapping;

    // 对于登录接口，直接放行
    @SneakyThrows
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        if (SecurityUtil.validateRequest(request)) {
            chain.doFilter(request, response);
            return;
        }
        UserDetails user = SecurityContextHolder.getCurrentUser();
        log.info("开始校验用户{}的权限", user.getUsername());
        //todo 如何知道接口需要哪些权限？ 如何在过滤器中拿到接口上的注解？
        HttpServletRequest req = SecurityUtil.toHttpServletRequest(request);
        // 下面这种方式拿到的是null
        Object handler = req.getAttribute(HandlerMapping.BEST_MATCHING_HANDLER_ATTRIBUTE);

        if (handler instanceof HandlerMethod) {
            HandlerMethod method = (HandlerMethod) handler;
            PreAuthorize authorize = method.getMethodAnnotation(PreAuthorize.class);
            if (authorize == null) {
                chain.doFilter(request, response);
                return; // 默认是不需要任何权限，直接可以访问接口
            }
            String apiPermission = authorize.value();
            for (String authority : user.getAuthorities()) {
                if (antPathMatcher.match(authority, apiPermission)) {
                    chain.doFilter(request, response);
                    return;
                }
            }
            HttpServletResponse resp = SecurityUtil.toHttpServletResponse(response);
            try (PrintWriter writer = resp.getWriter()) {
                RespBean respBean = RespBean.fail(ResultEnum.USER_NOT_AUTHORIZED);
                writer.write(JSON.toJson(respBean));
            }
            return;
        }
        chain.doFilter(request, response);
    }

    /**
     * 利用AntPathMatcher来实现权限匹配
     */
    public static void main(String[] args) {
        AntPathMatcher matcher = new AntPathMatcher();
        boolean match = matcher.match("user:create", "user:create");
        System.out.println(match);
    }

}
